package com.dutiantech.file.core;

import java.io.ByteArrayInputStream ;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dutiantech.rambo.exception.RamboRunTimeException;
import com.dutiantech.rambo.tool.basic.DTStrUtil;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;

public class SFTPInstance implements FileManager{

	private final Logger logger = LoggerFactory.getLogger(getClass());
	
    Session session = null;
    ChannelSftp sftp = null ;
	int timeout = 30 ;
	int retryCount = 0 ;
	int retryMax = 10 ;
	
	
	class SFTPMonitor extends TimerTask implements SftpProgressMonitor{
		
		String name = getClass().getSimpleName();
		boolean isProccess = false ;
		Timer timer; // 定时器对象
		long progressInterval = 3 * 1000;
		long tmpCount ;
		
		public SFTPMonitor(String name ) {
			this.name = name ;
		}
		
		long transfered = 0 ;
		
		void start() {
			if( timer == null ) {
				timer = new Timer() ;
			}

	        timer.schedule(this, 1000 , progressInterval);  
	        isProccess = true ;
		}
		
		void stop() {
			isProccess = false ;
			if( timer != null ) {
				timer.cancel(); 
				timer.purge() ;
				timer = null ;
			}
		}
		
		@Override
		public void init(int op, String src, String dest, long max) {
			transfered = 0 ;
			logger.info(format("[%s]->开始执行任务：op=[%d],src=[%s],dest=[%s],max=[%d]" , name ,
					op , src , dest , max ));
			start() ;
		}

		@Override
		public boolean count(long count) {
			transfered += count ;
			tmpCount += count ;
			return true;
		}

		@Override
		public void end() {
			end() ;
			logger.info(format("任务结束，共完成 %d Bytes传送", transfered ) );
		}
		
		String formatValue(long dumpVal ) {
			String aft = "bytes";
			if( dumpVal > 1024 ) {
				dumpVal = dumpVal/1024 ;
				aft = "KB" ;
				if( dumpVal > 1024 ) {
					dumpVal = dumpVal/1024 ;
					aft = "MB";
				}
			}
			return dumpVal + "" + aft ;
		}
		
		@Override
		public void run() {
			
			if( isProccess ) {
				//dump
				logger.info( format("[%s]->当前操作进度：[%s],速度：[%s]", name ,formatValue( transfered ) , formatValue(tmpCount/2)) );
				tmpCount = 0 ;
			}
			
		}
		
	}
    
	String format(String str , Object ...args ) {
		return String.format( str , args) ;
	}
	
	boolean isRetryLogin( ) {

		if( retryCount < retryMax ) {
			retryCount ++ ;
			logger.error(format("创建通道失败,重试 %d/%d" , retryCount , retryMax ));
			try {
				Thread.sleep(1*1000);
			} catch (InterruptedException e1) {
			}
			return true ;
		}
		return false ;
	}
	
	@Override
	public boolean login(String userName, String password, String host, int port, boolean... isPassiveMode) {

		JSch jsch = new JSch(); // 创建JSch对象
	    Channel channel = null;
	    
		logger.info( format("创建sftp连接配置--->[%s:%d],用户:[%s]" , host , port , userName ) );
		try {
			// 根据用户名，主机ip，端口获取一个Session对象
			session = jsch.getSession( userName , host , port );
		} catch (JSchException e) {
			logger.error(format("创建连接配置失败,[%s][%d][%s],错误原因:[%s]",host , port , userName , e.getMessage() ));
			return false ;
		}

		logger.info("连接配置创建成功..");
		logger.info("设置连接超时时间为 " + timeout + "秒");
		
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config); 			// 为Session对象设置properties
        session.setConfig("userauth.gssapi-with-mic", "no") ;
        session.setPassword( password );
        try {
			session.setTimeout(timeout);	// 设置timeout时间
	        session.connect(); 				// 通过Session建立链接
		} catch (JSchException e) {
			logger.error("连接sftp服务器失败,详细原因:" + e.getMessage() );
			if( isRetryLogin() )
				return login(userName, password, host, port) ;
			return false ;
		} 
        
        logger.info("连接sftp服务器成功,正在打开通道。");
        
        try {
			channel = session.openChannel("sftp") ;
			channel.connect(); 
			sftp = (ChannelSftp)channel ;
		} catch (JSchException e) {
			logger.error("打开sftp失败,原因：" + e.getMessage() );
			if( isRetryLogin() )
				return login(userName, password, host, port) ;
			return false ;
		}
		 
		return true ;
	}	
	
	@Override
	public boolean put( String fileName, byte[] body) {
		
		InputStream input = new ByteArrayInputStream(body);
		
		return put( fileName , input );
	}

	@Override
	public boolean put(String fileName, InputStream in) {
		
		File file = new File( fileName ) ;
		String remotePath = file.getParent() ;
		
		if( DTStrUtil.isEmpty(remotePath) == false ) {
			boolean chooseResult = cd(remotePath) ;
			if( chooseResult == false ) {
				boolean createResult = mkdir( remotePath ) ;
				if( createResult == false ) {
					logger.error(format("创建服务器目录失败,[%s]" , remotePath ));
					throw new RamboRunTimeException("创建服务器目录失败," + remotePath ) ;
				}
			}
		}
		
		try {
			sftp.put(in, file.getAbsoluteFile().getName() , new SFTPMonitor("上传" + file.getName()) );
		} catch (SftpException e) {
			logger.error("上传文件失败," + e.getMessage() );
			return false ;
		}
		
		return true ;
	}

	
	@Override
	public boolean put(String fileName, File file ) {
		checkState();
		
		try {
			return put( fileName , new FileInputStream( file) ) ;
		} catch (FileNotFoundException e) {
			logger.error(file.getAbsoluteFile().getAbsolutePath() + " 未找到 ," + e.getMessage() );
			return false;
		}
	}


	@Override
	public boolean download(String savePath, String saveFileName, String remoteFileName) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public InputStream download(String remoteFileName) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean cd(String floderName) {
		try {
			sftp.cd(floderName);
		} catch (SftpException e) {
			return false ;
		}
		return true;
	}

	/**
	 * 新建目录并cd进去，支持多级目录，已存在则直接cd进去
	 */
	@Override
	public boolean mkdir(String dirPath) {
		try {
			String[] paths = dirPath.split(getSeparator()) ; 
			for(String path : paths ) {
				boolean result = cd(path) ;
				if( result == false ) {
					sftp.mkdir(path);
					cd(path) ;
				}
			}
		} catch (SftpException e) {
			return false ;
		}
		
		return true;
	}
	

	/**
	 * 查询所有目录
	 */
	@Override
	public Vector<String> lsDirectory() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 查询所有文件
	 */
	@Override
	public Vector<String> lsFiles() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Vector<String> lsFiles(String pathname, FTPFileFilter filter) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 返回上层
	 */
	public boolean changeToParentDirectory() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean remove(String file) {
		try {
			sftp.rm(file);
		} catch (SftpException e) {
			return false ;
		}
		return true ;
	}

	@Override
	public void checkState() throws RamboRunTimeException {
		if( sftp == null )
			throw new RamboRunTimeException("渠道未初始化") ;
	}

	@Override
	public void exit() {
		if( sftp != null ) {
			if( sftp.isConnected() ) {
				sftp.disconnect();
				logger.info("断开SFTP连接");
			}
		}
		
		if( session != null ) {
			if( session.isConnected() )
				session.disconnect();
		}
	}

	String getSeparator() {
		if( isWindow() )
			return "\\\\";
		else
			return File.separator ;
	}
	
	boolean isWindow() {
		String osName = System.getProperty("os.name") ;
		return osName.indexOf("Window") >= 0 ;
	}
	
}
